//
// Created by 24100 on 2022/3/23.
//

#include "GeoSphere.h"

GeoSphere::GeoSphere(float mRadius, float mWSegments, float mHeightSegments, float mPhiStart, float mPhiLength,
					 float mThetaStart, float mThetaLength) : m_radius(mRadius), m_wSegments(mWSegments),
															  m_hSegments(mHeightSegments), m_phiStart(mPhiStart),
															  m_phiLength(mPhiLength), m_thetaStart(mThetaStart),
															  m_thetaLength(mThetaLength)
{
	makeData();
}

void GeoSphere::makeData()
{
	Vertices vertices;
	Indices indices;
	const float thetaEnd = glm::min(m_thetaStart + m_thetaLength, PI);
	int index = 0;

	m_wSegments = glm::max(3.0f, glm::floor(m_wSegments));
	m_hSegments = glm::max(2.0f, glm::floor(m_hSegments));

	std::vector<std::vector<int>> grid;

	glm::vec3 position = glm::vec3(0.0f);
	glm::vec3 normal = glm::vec3(0.0f);

	Vertex vertex;

	// 计算 vertices normals 和 uvs
	for (unsigned int iy = 0; iy <= m_hSegments; iy++)
	{
		std::vector<int> verticesRow;

		float v = iy / m_hSegments;

		float uOffset = 0;

		if (iy == 0 && m_thetaStart == 0)
		{
			uOffset = 0.5 / m_wSegments;
		}
		else if (iy == m_hSegments && thetaEnd == PI)
		{
			uOffset = -0.5 / m_wSegments;
		}
		for (unsigned int ix = 0; ix <= m_wSegments; ix++)
		{
			const float u = ix / m_wSegments;

			// position
			position.x = -m_radius * glm::cos(m_phiStart + u * m_phiLength) * glm::sin(m_thetaStart + v * m_thetaLength);
			position.y = m_radius * glm::cos(m_thetaStart + v * m_thetaLength);
			position.z = m_radius * glm::sin(m_phiStart + u * m_phiLength) * glm::sin(m_thetaStart + v * m_thetaLength);

			vertex.Position = position;

			// uv
			vertex.TexCoords = glm::vec2(u + uOffset, 1 - v);

			vertices.push_back(vertex);

			verticesRow.push_back(index++);
		}
		grid.push_back(verticesRow);
	}

	// indices
	for (unsigned int iy = 0; iy < m_hSegments; iy++)
	{
		for (unsigned ix = 0; ix < m_wSegments; ix++)
		{
			unsigned int a = grid[iy][ix + 1];
			unsigned int b = grid[iy][ix];
			unsigned int c = grid[iy + 1][ix];
			unsigned int d = grid[iy + 1][ix + 1];

			if (iy != 0 || m_thetaStart > 0)
			{
				indices.push_back(a);
				indices.push_back(b);
				indices.push_back(d);
			}
			if (iy != m_hSegments - 1 || thetaEnd < PI)
			{
				indices.push_back(b);
				indices.push_back(c);
				indices.push_back(d);
			}
		}
		setup(vertices, indices);
	}
}
